use sqlx::{PgPool};
use crate::errors::MyError;
use crate::models::course::{Course, CreateCourse, UpdateCourse};

pub async fn get_course_for_teacher(pool: &PgPool, teacher_id: i32) -> Result<Vec<Course>, MyError> {
    sqlx::query_as!(
            Course,
            r#"
            SELECT *
            FROM course
            WHERE teacher_id =$1
            "#,
            teacher_id
        )
        .fetch_all(pool)
        .await
        .map_err(sqlx::error::Error::into)
}

pub async fn course(pool: &PgPool, new_course: CreateCourse) -> Result<Course, MyError> {
    let description = if let Some(description) = new_course.description {
        description
    } else {
        "".to_string()
    };

    let format = if let Some(format) = new_course.format {
        format
    } else {
        "".to_string()
    };

    let structure = if let Some(structure) = new_course.structure {
        structure
    } else {
        "".to_string()
    };

    let duration = if let Some(duration) = new_course.duration {
        duration
    } else {
        "".to_string()
    };
    let price = if let Some(price) = new_course.price {
        price
    } else {
        0
    };
    let language = if let Some(language) = new_course.language {
        language
    } else {
        "".to_string()
    };
    let level = if let Some(level) = new_course.level {
        level
    } else {
        "".to_string()
    };

    sqlx::query_as!(
            Course,
            r#"
            INSERT INTO
            course(name,teacher_id,description,format,structure,duration,price,language,level)
            VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9)
            returning id,name,teacher_id,time,description,format,structure,duration,price,language,level
            "#,
            new_course.name,
            new_course.teacher_id,
            description,
            format,
            structure,
            duration,
            price,
            language,
            level
        )
        .fetch_one(pool)
        .await
        .map_err(sqlx::error::Error::into)
}

pub async fn update_course_details(
    pool: &PgPool,
    teacher_id: i32,
    course_id: i32,
    update_course: UpdateCourse,
) -> Result<Course, MyError> {
    let current_course_row = sqlx::query_as!(
            Course,
            r#"
               select * from course where teacher_id =$1 and id = $2
            "#,
            teacher_id,
            course_id
        ).fetch_one(pool)
        .await
        .map_err(|_err| MyError::NotFound("Course Id not found".into()))?
        ;

    let name = if let Some(name) = update_course.name {
        name
    } else {
        current_course_row.name
    };

    let description = if let Some(description) = update_course.description {
        description
    } else {
        current_course_row.description
    };
    let format = if let Some(format) = update_course.format {
        format
    } else {
        current_course_row.format
    };
    let structure = if let Some(structure) = update_course.structure {
        structure
    } else {
        current_course_row.structure
    };
    let duration = if let Some(duration) = update_course.duration {
        duration
    } else {
        current_course_row.duration
    };
    let price = if let Some(price) = update_course.price {
        price
    } else {
        current_course_row.price
    };
    let language = if let Some(language) = update_course.language {
        language
    } else {
        current_course_row.language
    };
    let level = if let Some(level) = update_course.level {
        level
    } else {
        current_course_row.level
    };

    sqlx::query_as!(
            Course,
            r#"
            update course
            set name=$1,
            description=$2,
            format=$3,
            structure=$4,
            duration=$5,
            price=$6,
            language=$7,
            level=$8
            where teacher_id=$9 and id=$10
            returning id,teacher_id,name,time,description,format,structure,duration,price,language,level
            "#,
            name,
            description,
            format,
            structure,
            duration,
            price,
            language,
            level,
            teacher_id,
            course_id
        )
        .fetch_one(pool)
        .await
        .map_err(sqlx::error::Error::into)
}


pub async fn get_course_detail(pool: &PgPool, teacher_id: i32, course_id: i32) -> Result<Course, MyError> {
    sqlx::query_as!(
            Course,
            r#"
                SELECT *
                FROM course
                WHERE teacher_id =$1 AND id = $2
            "#,
            teacher_id,
            course_id
        )
        .fetch_optional(pool)
        .await
        .map_err(sqlx::error::Error::into)
        .and_then(|opt| opt.ok_or(MyError::NotFound("Course id not found".into())))
}

pub async fn delete_course(pool: &PgPool, teacher_id: i32, course_id: i32) -> Result<String, MyError> {
    let course_row = sqlx::query!(
            "delete from course where teacher_id=$1 and id=$2",
            teacher_id,
            course_id,
        )
        .execute(pool)
        .await?;

    Ok(format!("Deleted {:?} record", course_row))
}

pub async fn get_course_all(pool: &PgPool) -> Result<Vec<Course>, MyError> {
    sqlx::query_as!(
            Course,
            r#"
            SELECT *
            FROM course
            "#)
        .fetch_all(pool)
        .await
        .map_err(sqlx::error::Error::into)
}

#[cfg(test)]
mod test {
    use super::*;
    use actix_web::http::StatusCode;
    use std::sync::Mutex;

    #[actix_rt::test]
    async fn get_all_course_success() {}
}

